/*
 * Copyright 2017 hv0912
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.vimhe.ezimp2.config;

import com.vimhe.ezimp2.config.bean.ColumnConfig;
import com.vimhe.ezimp2.config.bean.Configuration;
import com.vimhe.ezimp2.config.bean.FileConfig;
import com.vimhe.ezimp2.config.bean.FormatterConfig;
import com.vimhe.ezimp2.config.bean.RowConfig;
import com.vimhe.ezimp2.config.bean.SheetConfig;
import com.vimhe.ezimp2.config.bean.ValidatorConfig;
import com.vimhe.ezimp2.config.exception.ConfigException;
import com.vimhe.ezimp2.util.StringUtils;
import com.vimhe.ezimp2.util.ValidateUtils;

import java.util.HashMap;

/**
 * 抽象配置源
 *
 * <p>通过继承该类来快速地实现自定义的配置源</p>
 *
 * @author Vimhe
 */
public abstract class AbstractConfigSource implements ConfigSource {

    private Configuration configuration;

    @Override
    public final Configuration read() {
        if (configuration == null) {
            configuration = new Configuration();
            try {
                process();
            } catch (Exception e) {
                throw new ConfigException("解析配置失败：" + e.getMessage(), e);
            }
        }
        return configuration;
    }

    /**
     * 每读取一个文件的配置
     *
     * @param fileConfig 文件配置对象
     */
    protected final void read(FileConfig fileConfig) {
        if (ValidateUtils.isEmpty(configuration.getFileConfigMap())) {
            configuration.setFileConfigMap(new HashMap<String, FileConfig>(16));
        }

        configuration.getFileConfigMap().put(fileConfig.getIndex(), fileConfig);
    }

    /**
     * 每读取一个工作表的配置
     *
     * @param fileIndex   当前文件索引
     * @param sheetConfig 工作表配置对象
     */
    protected final void read(String fileIndex, SheetConfig sheetConfig) {
        FileConfig fileConfig = configuration.getFileConfigMap().get(fileIndex);
        if (ValidateUtils.isEmpty(fileConfig.getSheetConfigMap())) {
            fileConfig.setSheetConfigMap(new HashMap<Integer, SheetConfig>(16));
        }

        fileConfig.getSheetConfigMap().put(sheetConfig.getIndex(), sheetConfig);
    }

    /**
     * 每读取一行的配置
     *
     * @param fileIndex  当前文件索引
     * @param sheetIndex 当前工作表索引
     * @param rowConfig  行配置对象
     */
    protected final void read(String fileIndex, Integer sheetIndex, RowConfig rowConfig) {
        SheetConfig sheetConfig = configuration
                .getFileConfigMap().get(fileIndex)
                .getSheetConfigMap().get(sheetIndex);
        if (ValidateUtils.isEmpty(sheetConfig.getRowConfig())) {
            sheetConfig.setRowConfig(rowConfig);
        }
    }

    /**
     * 每读取一个单元格的配置
     *
     * @param fileIndex    当前文件索引
     * @param sheetIndex   当前工作表索引
     * @param columnConfig 单元格配置对象
     */
    protected final void read(String fileIndex, Integer sheetIndex, ColumnConfig columnConfig) {
        RowConfig rowConfig = configuration
                .getFileConfigMap().get(fileIndex)
                .getSheetConfigMap().get(sheetIndex)
                .getRowConfig();
        if (ValidateUtils.isEmpty(rowConfig.getColumnConfigMap())) {
            rowConfig.setColumnConfigMap(new HashMap<String, ColumnConfig>(32));
        }

        rowConfig.getColumnConfigMap().put(columnConfig.getIndex(), columnConfig);
    }

    /**
     * 每读取一个验证器的配置
     *
     * @param fileIndex       当前文件索引
     * @param sheetIndex      当前工作表索引
     * @param columnIndex     当前单元格索引
     * @param validatorConfig 验证器配置对象
     */
    protected final void read(String fileIndex, Integer sheetIndex, String columnIndex, ValidatorConfig validatorConfig) {
        ColumnConfig columnConfig = configuration
                .getFileConfigMap().get(fileIndex)
                .getSheetConfigMap().get(sheetIndex)
                .getRowConfig()
                .getColumnConfigMap().get(columnIndex);
        if (ValidateUtils.isEmpty(columnConfig.getValidatorConfigMap())) {
            columnConfig.setValidatorConfigMap(new HashMap<String, ValidatorConfig>(16));
        }

        if (columnConfig.getValidatorConfigMap().get(validatorConfig.getName()) != null) {
            throw new ConfigException("当前单元格已分配名为【" + validatorConfig.getName() + "】的格式转换器，不能重复设置");
        }

        if (StringUtils.isBlank(validatorConfig.getMessage())) {
            validatorConfig.setMessage("数据不符合要求的规范");
        }
        columnConfig.getValidatorConfigMap().put(validatorConfig.getName(), validatorConfig);
    }

    /**
     * 每读取一个格式转换器的配置
     *
     * @param fileIndex       当前文件索引
     * @param sheetIndex      当前工作表索引
     * @param columnIndex     当前单元格索引
     * @param formatterConfig 数据格式转换器配置对象
     */
    protected final void read(String fileIndex, Integer sheetIndex, String columnIndex, FormatterConfig formatterConfig) {
        ColumnConfig columnConfig = configuration
                .getFileConfigMap().get(fileIndex)
                .getSheetConfigMap().get(sheetIndex)
                .getRowConfig()
                .getColumnConfigMap().get(columnIndex);
        if (ValidateUtils.isEmpty(columnConfig.getFormatterConfigMap())) {
            columnConfig.setFormatterConfigMap(new HashMap<String, FormatterConfig>(16));
        }

        if (columnConfig.getFormatterConfigMap().size() > 1) {
            throw new ConfigException("一个单元格只能分配一个格式转换器");
        }

        if (StringUtils.isBlank(formatterConfig.getMessage())) {
            formatterConfig.setMessage("数据无法转换为期望的格式");
        }
        columnConfig.getFormatterConfigMap().put(formatterConfig.getName(), formatterConfig);
    }

    /**
     * 读取配置源
     *
     * @throws Exception 读取配置源的过程中发生异常
     */
    protected abstract void process() throws Exception;

}
